import tkinter as tk
from tkinter import messagebox, filedialog
import customtkinter
from datetime import datetime
import os
import threading
from ssh_client import SSHClient
from logger_config import logger


# 日志窗口
class LogWindow(customtkinter.CTkToplevel):
    def __init__(self, parent):
        super().__init__(parent)
        self.title("操作日志")
        self.geometry("800x600")  # 保持较大尺寸，适合查看日志
        self.parent = parent

        # 确保窗口置顶显示
        self.transient(parent)
        self.grab_set()
        self.lift()

        # 创建文本框显示日志
        self.log_text = customtkinter.CTkTextbox(self, wrap=tk.WORD)
        self.log_text.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
        self.log_text.configure(state=tk.DISABLED)

        # 添加滚动条
        scrollbar = customtkinter.CTkScrollbar(self, command=self.log_text.yview)
        scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
        self.log_text.configure(yscrollcommand=scrollbar.set)

        # 加载最新日志
        self.load_logs()

    def load_logs(self):
        """加载最新的日志内容"""
        try:
            from main import log_dir
            log_file = os.path.join(log_dir, f"{datetime.now().strftime('%Y%m%d')}.log")
            if os.path.exists(log_file):
                with open(log_file, "r", encoding="utf-8") as f:
                    logs = f.read()
                    self.log_text.configure(state=tk.NORMAL)
                    self.log_text.delete(1.0, tk.END)
                    self.log_text.insert(tk.END, logs)
                    self.log_text.see(tk.END)
                    self.log_text.configure(state=tk.DISABLED)
        except Exception as e:
            print(f"加载日志失败: {str(e)}")

    def append_log(self, message):
        """追加日志到文本框"""
        self.log_text.configure(state=tk.NORMAL)
        self.log_text.insert(tk.END, f"{datetime.now().strftime('%Y-%m-%d %H:%M:%S')} - {message}\n")
        self.log_text.see(tk.END)
        self.log_text.configure(state=tk.DISABLED)


# 服务器配置窗口
class ServerConfigWindow(customtkinter.CTkToplevel):
    def __init__(self, parent, db, server_id=None):
        super().__init__(parent)
        self.title("服务器配置" if not server_id else "编辑服务器")
        self.geometry("500x450")  # 增加高度，从350→400
        self.parent = parent
        self.db = db
        self.server_id = server_id
        self.server_data = None

        # 确保窗口置顶显示
        self.transient(parent)
        self.grab_set()
        self.lift()

        if server_id:
            self.server_data = self.db.get_server_by_id(server_id)

        self.init_ui()

    def init_ui(self):
        # 创建主容器，增加内边距
        main_container = customtkinter.CTkFrame(self)
        main_container.pack(fill=tk.BOTH, expand=True, padx=20, pady=20)

        # 创建表单框架
        frame = customtkinter.CTkFrame(main_container)
        frame.pack(fill=tk.BOTH, expand=True)

        # 服务器名称
        customtkinter.CTkLabel(frame, text="服务器名称:").grid(row=0, column=0, sticky=tk.W, padx=5, pady=8)
        self.name_entry = customtkinter.CTkEntry(frame, width=300)
        self.name_entry.grid(row=0, column=1, sticky=tk.W, padx=5, pady=8)

        # IP地址
        customtkinter.CTkLabel(frame, text="IP地址:").grid(row=1, column=0, sticky=tk.W, padx=5, pady=8)
        self.ip_entry = customtkinter.CTkEntry(frame, width=300)
        self.ip_entry.grid(row=1, column=1, sticky=tk.W, padx=5, pady=8)

        # 端口
        customtkinter.CTkLabel(frame, text="端口:").grid(row=2, column=0, sticky=tk.W, padx=5, pady=8)
        self.port_entry = customtkinter.CTkEntry(frame, width=300)
        self.port_entry.insert(0, "22")
        self.port_entry.grid(row=2, column=1, sticky=tk.W, padx=5, pady=8)

        # 用户名
        customtkinter.CTkLabel(frame, text="用户名:").grid(row=3, column=0, sticky=tk.W, padx=5, pady=8)
        self.username_entry = customtkinter.CTkEntry(frame, width=300)
        self.username_entry.grid(row=3, column=1, sticky=tk.W, padx=5, pady=8)

        # 密码
        customtkinter.CTkLabel(frame, text="密码:").grid(row=4, column=0, sticky=tk.W, padx=5, pady=8)
        self.password_entry = customtkinter.CTkEntry(frame, width=300, show="*")
        self.password_entry.grid(row=4, column=1, sticky=tk.W, padx=5, pady=8)

        # 描述
        customtkinter.CTkLabel(frame, text="描述:").grid(row=5, column=0, sticky=tk.NW, padx=5, pady=8)
        self.desc_text = customtkinter.CTkTextbox(frame, width=300, height=80)
        self.desc_text.grid(row=5, column=1, sticky=tk.W, padx=5, pady=8)

        # 按钮区域 - 独立框架，确保在底部显示
        btn_frame = customtkinter.CTkFrame(self)
        btn_frame.pack(fill=tk.X, padx=20, pady=15)  # 增加底部边距

        self.test_conn_btn = customtkinter.CTkButton(btn_frame, text="测试连通性", command=self.test_connection)
        self.test_conn_btn.pack(side=tk.LEFT, padx=10)

        self.save_btn = customtkinter.CTkButton(btn_frame, text="保存", command=self.save_server)
        self.save_btn.pack(side=tk.LEFT, padx=10)

        self.cancel_btn = customtkinter.CTkButton(btn_frame, text="取消", command=self.destroy)
        self.cancel_btn.pack(side=tk.RIGHT, padx=10)

        # 如果是编辑模式，加载数据
        if self.server_data:
            self.name_entry.insert(0, self.server_data[1])
            self.ip_entry.insert(0, self.server_data[2])
            self.port_entry.insert(0, self.server_data[3])
            self.username_entry.insert(0, self.server_data[4])
            self.password_entry.insert(0, self.server_data[5])
            self.desc_text.insert(tk.END, self.server_data[6] or "")

    def test_connection(self):
        """测试与服务器的连接"""
        # 获取表单数据
        name = self.name_entry.get().strip()
        ip = self.ip_entry.get().strip()
        port = self.port_entry.get().strip()
        username = self.username_entry.get().strip()
        password = self.password_entry.get().strip()

        # 基本验证
        if not ip:
            messagebox.showerror("错误", "IP地址不能为空")
            return

        try:
            port = int(port)
            if port < 1 or port > 65535:
                raise ValueError
        except ValueError:
            messagebox.showerror("错误", "端口必须是1-65535之间的整数")
            return

        if not username:
            messagebox.showerror("错误", "用户名不能为空")
            return

        if not password:
            messagebox.showerror("错误", "密码不能为空")
            return

        # 显示正在连接提示
        self.test_conn_btn.configure(text="连接中...", state=tk.DISABLED)
        self.update()

        # 在新线程中测试连接，避免界面卡顿
        def connect_thread():
            server_info = (None, name, ip, port, username, password, "")
            ssh_client = SSHClient(server_info)
            success = ssh_client.connect()
            ssh_client.disconnect()

            # 恢复按钮状态并显示结果
            self.test_conn_btn.configure(text="测试连通性", state=tk.NORMAL)

            if success:
                messagebox.showinfo("成功", f"已成功连接到服务器 {ip}:{port}")
                logger.info(f"测试连接成功: {ip}:{port}")
            else:
                messagebox.showerror("失败", f"无法连接到服务器 {ip}:{port}\n请检查配置是否正确")
                logger.error(f"测试连接失败: {ip}:{port}")

        threading.Thread(target=connect_thread, daemon=True).start()

    def save_server(self):
        name = self.name_entry.get().strip()
        ip = self.ip_entry.get().strip()
        port = self.port_entry.get().strip()
        username = self.username_entry.get().strip()
        password = self.password_entry.get().strip()
        desc = self.desc_text.get(1.0, tk.END).strip()

        # 验证
        if not name:
            messagebox.showerror("错误", "服务器名称不能为空")
            return

        if not ip:
            messagebox.showerror("错误", "IP地址不能为空")
            return

        try:
            port = int(port)
            if port < 1 or port > 65535:
                raise ValueError
        except ValueError:
            messagebox.showerror("错误", "端口必须是1-65535之间的整数")
            return

        if not username:
            messagebox.showerror("错误", "用户名不能为空")
            return

        if not password:
            messagebox.showerror("错误", "密码不能为空")
            return

        # 保存
        try:
            if self.server_id:
                self.db.update_server(self.server_id, name, ip, port, username, password, desc)
                messagebox.showinfo("成功", "服务器信息更新成功")
                logger.info(f"更新服务器: {name}({ip})")
            else:
                self.db.add_server(name, ip, port, username, password, desc)
                messagebox.showinfo("成功", "服务器添加成功")
                logger.info(f"添加服务器: {name}({ip})")

            self.parent.refresh_server_list()
            self.destroy()
        except Exception as e:
            messagebox.showerror("错误", f"保存失败: {str(e)}")
            logger.error(f"保存服务器失败: {str(e)}")


# 数据库配置窗口
class DbConfigWindow(customtkinter.CTkToplevel):
    def __init__(self, parent, db, server_id, config_id=None):
        super().__init__(parent)
        self.title("数据库配置" if not config_id else "编辑数据库配置")
        self.geometry("500x500")  # 增加高度，从400→450
        self.parent = parent
        self.db = db
        self.server_id = server_id
        self.config_id = config_id
        self.config_data = None

        # 确保窗口置顶显示
        self.transient(parent)
        self.grab_set()
        self.lift()

        if config_id:
            self.config_data = self.db.get_db_config_by_id(config_id)

        self.init_ui()

    def init_ui(self):
        # 创建主容器
        main_container = customtkinter.CTkFrame(self)
        main_container.pack(fill=tk.BOTH, expand=True, padx=20, pady=20)

        # 创建表单框架
        frame = customtkinter.CTkFrame(main_container)
        frame.pack(fill=tk.BOTH, expand=True)

        # 配置名称
        customtkinter.CTkLabel(frame, text="配置名称:").grid(row=0, column=0, sticky=tk.W, padx=5, pady=8)
        self.name_entry = customtkinter.CTkEntry(frame, width=300)
        self.name_entry.grid(row=0, column=1, sticky=tk.W, padx=5, pady=8)

        # 数据库类型
        customtkinter.CTkLabel(frame, text="数据库类型:").grid(row=1, column=0, sticky=tk.W, padx=5, pady=8)
        self.type_var = tk.StringVar(value="mysql")
        self.type_combo = customtkinter.CTkComboBox(frame, width=300,
                                                    values=["mysql", "postgresql", "oracle", "sqlserver", "other"],
                                                    variable=self.type_var)
        self.type_combo.grid(row=1, column=1, sticky=tk.W, padx=5, pady=8)

        # 主机地址
        customtkinter.CTkLabel(frame, text="主机地址:").grid(row=2, column=0, sticky=tk.W, padx=5, pady=8)
        self.host_entry = customtkinter.CTkEntry(frame, width=300)
        self.host_entry.grid(row=2, column=1, sticky=tk.W, padx=5, pady=8)

        # 端口
        customtkinter.CTkLabel(frame, text="端口:").grid(row=3, column=0, sticky=tk.W, padx=5, pady=8)
        self.port_entry = customtkinter.CTkEntry(frame, width=300)
        self.port_entry.insert(0, "3306")  # 默认MySQL端口
        self.port_entry.grid(row=3, column=1, sticky=tk.W, padx=5, pady=8)

        # 数据库名
        customtkinter.CTkLabel(frame, text="数据库名:").grid(row=4, column=0, sticky=tk.W, padx=5, pady=8)
        self.dbname_entry = customtkinter.CTkEntry(frame, width=300)
        self.dbname_entry.grid(row=4, column=1, sticky=tk.W, padx=5, pady=8)

        # 用户名
        customtkinter.CTkLabel(frame, text="用户名:").grid(row=5, column=0, sticky=tk.W, padx=5, pady=8)
        self.username_entry = customtkinter.CTkEntry(frame, width=300)
        self.username_entry.grid(row=5, column=1, sticky=tk.W, padx=5, pady=8)

        # 密码
        customtkinter.CTkLabel(frame, text="密码:").grid(row=6, column=0, sticky=tk.W, padx=5, pady=8)
        self.password_entry = customtkinter.CTkEntry(frame, width=300, show="*")
        self.password_entry.grid(row=6, column=1, sticky=tk.W, padx=5, pady=8)

        # 描述
        customtkinter.CTkLabel(frame, text="描述:").grid(row=7, column=0, sticky=tk.NW, padx=5, pady=8)
        self.desc_text = customtkinter.CTkTextbox(frame, width=300, height=60)
        self.desc_text.grid(row=7, column=1, sticky=tk.W, padx=5, pady=8)

        # 按钮区域
        btn_frame = customtkinter.CTkFrame(self)
        btn_frame.pack(fill=tk.X, padx=20, pady=15)  # 增加底部边距

        self.save_btn = customtkinter.CTkButton(btn_frame, text="保存", command=self.save_config)
        self.save_btn.pack(side=tk.LEFT, padx=10)

        self.cancel_btn = customtkinter.CTkButton(btn_frame, text="取消", command=self.destroy)
        self.cancel_btn.pack(side=tk.RIGHT, padx=10)

        # 如果是编辑模式，加载数据
        if self.config_data:
            self.name_entry.insert(0, self.config_data[1])
            self.type_var.set(self.config_data[2])
            self.host_entry.insert(0, self.config_data[3])
            self.port_entry.insert(0, self.config_data[4])
            self.dbname_entry.insert(0, self.config_data[5])
            self.username_entry.insert(0, self.config_data[6])
            self.password_entry.insert(0, self.config_data[7])
            self.desc_text.insert(tk.END, self.config_data[8] or "")

    def save_config(self):
        # 保存逻辑保持不变
        name = self.name_entry.get().strip()
        type_ = self.type_var.get()
        host = self.host_entry.get().strip()
        port = self.port_entry.get().strip()
        database = self.dbname_entry.get().strip()
        username = self.username_entry.get().strip()
        password = self.password_entry.get().strip()
        desc = self.desc_text.get(1.0, tk.END).strip()

        # 验证
        if not name:
            messagebox.showerror("错误", "配置名称不能为空")
            return

        if not host:
            messagebox.showerror("错误", "主机地址不能为空")
            return

        try:
            port = int(port)
            if port < 1 or port > 65535:
                raise ValueError
        except ValueError:
            messagebox.showerror("错误", "端口必须是1-65535之间的整数")
            return

        if not database:
            messagebox.showerror("错误", "数据库名不能为空")
            return

        if not username:
            messagebox.showerror("错误", "用户名不能为空")
            return

        # 保存
        try:
            if self.config_id:
                self.db.update_db_config(self.config_id, self.server_id, name, type_, host, port, database, username,
                                         password, desc)
                messagebox.showinfo("成功", "数据库配置更新成功")
                logger.info(f"更新数据库配置: {name}")
            else:
                self.db.add_db_config(self.server_id, name, type_, host, port, database, username, password, desc)
                messagebox.showinfo("成功", "数据库配置添加成功")
                logger.info(f"添加数据库配置: {name}")

            self.parent.refresh_db_config_list(self.server_id)
            self.destroy()
        except Exception as e:
            messagebox.showerror("错误", f"保存失败: {str(e)}")
            logger.error(f"保存数据库配置失败: {str(e)}")


# 项目配置窗口
class ProjectConfigWindow(customtkinter.CTkToplevel):
    def __init__(self, parent, db, server_id, project_id=None):
        super().__init__(parent)
        self.title("项目配置" if not project_id else "编辑项目")
        self.geometry("600x550")  # 增加高度，从500→550
        self.parent = parent
        self.db = db
        self.server_id = server_id
        self.project_id = project_id
        self.project_data = None

        # 确保窗口置顶显示
        self.transient(parent)
        self.grab_set()
        self.lift()

        if project_id:
            self.project_data = self.db.get_project_by_id(project_id)

        self.init_ui()

    def init_ui(self):
        # 创建主容器
        main_container = customtkinter.CTkFrame(self)
        main_container.pack(fill=tk.BOTH, expand=True, padx=20, pady=20)

        # 创建表单框架
        frame = customtkinter.CTkFrame(main_container)
        frame.pack(fill=tk.BOTH, expand=True)

        # 项目名称
        customtkinter.CTkLabel(frame, text="项目名称:").grid(row=0, column=0, sticky=tk.W, padx=5, pady=8)
        self.name_entry = customtkinter.CTkEntry(frame, width=350)
        self.name_entry.grid(row=0, column=1, sticky=tk.W, padx=5, pady=8)

        # 项目类型
        customtkinter.CTkLabel(frame, text="项目类型:").grid(row=1, column=0, sticky=tk.W, padx=5, pady=8)
        self.type_var = tk.StringVar(value="vue")
        self.type_frame = customtkinter.CTkFrame(frame)
        self.type_frame.grid(row=1, column=1, sticky=tk.W, padx=5, pady=8)

        self.vue_radio = customtkinter.CTkRadioButton(self.type_frame, text="Vue前端", variable=self.type_var,
                                                      value="vue")
        self.vue_radio.pack(side=tk.LEFT, padx=10)

        self.jar_radio = customtkinter.CTkRadioButton(self.type_frame, text="JAR后端", variable=self.type_var,
                                                      value="jar")
        self.jar_radio.pack(side=tk.LEFT, padx=10)

        # 本地文件路径
        customtkinter.CTkLabel(frame, text="本地文件路径:").grid(row=2, column=0, sticky=tk.W, padx=5, pady=8)
        self.local_path_entry = customtkinter.CTkEntry(frame, width=300)
        self.local_path_entry.grid(row=2, column=1, sticky=tk.W, padx=5, pady=8)

        self.browse_local_btn = customtkinter.CTkButton(frame, text="浏览", width=40, command=self.browse_local_path)
        self.browse_local_btn.grid(row=2, column=2, sticky=tk.W, padx=5, pady=8)

        # 远程路径
        customtkinter.CTkLabel(frame, text="远程路径:").grid(row=3, column=0, sticky=tk.W, padx=5, pady=8)
        self.remote_path_entry = customtkinter.CTkEntry(frame, width=350)
        self.remote_path_entry.grid(row=3, column=1, sticky=tk.W, padx=5, pady=8)

        # 停止命令
        customtkinter.CTkLabel(frame, text="停止命令:").grid(row=4, column=0, sticky=tk.NW, padx=5, pady=8)
        self.stop_command_entry = customtkinter.CTkEntry(frame, width=350)
        self.stop_command_entry.grid(row=4, column=1, sticky=tk.W, padx=5, pady=8)

        # 启动命令
        customtkinter.CTkLabel(frame, text="启动命令:").grid(row=5, column=0, sticky=tk.NW, padx=5, pady=8)
        self.start_command_entry = customtkinter.CTkEntry(frame, width=350)
        self.start_command_entry.grid(row=5, column=1, sticky=tk.W, padx=5, pady=8)

        # 描述
        customtkinter.CTkLabel(frame, text="描述:").grid(row=6, column=0, sticky=tk.NW, padx=5, pady=8)
        self.desc_text = customtkinter.CTkTextbox(frame, width=350, height=80)
        self.desc_text.grid(row=6, column=1, sticky=tk.W, padx=5, pady=8)

        # 按钮区域
        btn_frame = customtkinter.CTkFrame(self)
        btn_frame.pack(fill=tk.X, padx=20, pady=15)  # 增加底部边距

        self.save_btn = customtkinter.CTkButton(btn_frame, text="保存", command=self.save_project)
        self.save_btn.pack(side=tk.LEFT, padx=10)

        self.cancel_btn = customtkinter.CTkButton(btn_frame, text="取消", command=self.destroy)
        self.cancel_btn.pack(side=tk.RIGHT, padx=10)

        # 如果是编辑模式，加载数据
        if self.project_data:
            self.name_entry.insert(0, self.project_data[2])
            self.type_var.set(self.project_data[3])
            self.local_path_entry.insert(0, self.project_data[4] or "")
            self.remote_path_entry.insert(0, self.project_data[5])
            self.stop_command_entry.insert(0, self.project_data[7] or "")
            self.start_command_entry.insert(0, self.project_data[6] or "")
            self.desc_text.insert(tk.END, self.project_data[8] or "")

    def browse_local_path(self):
        file_types = [("All Files", "*.*")]
        if self.type_var.get() == "vue":
            file_types.insert(0, ("Vue Build Files", "*.zip;*.tar.gz"))
        else:  # jar
            file_types.insert(0, ("JAR Files", "*.jar"))

        file_path = filedialog.askopenfilename(title="选择项目文件", filetypes=file_types)
        if file_path:
            self.local_path_entry.delete(0, tk.END)
            self.local_path_entry.insert(0, file_path)

    def save_project(self):
        # 保存逻辑保持不变
        name = self.name_entry.get().strip()
        type_ = self.type_var.get()
        local_path = self.local_path_entry.get().strip()
        remote_path = self.remote_path_entry.get().strip()
        start_command = self.start_command_entry.get().strip()
        stop_command = self.stop_command_entry.get().strip()
        desc = self.desc_text.get(1.0, tk.END).strip()

        # 验证
        if not name:
            messagebox.showerror("错误", "项目名称不能为空")
            return

        if not remote_path:
            messagebox.showerror("错误", "远程路径不能为空")
            return

        if local_path and not os.path.exists(local_path):
            messagebox.showerror("错误", f"本地文件不存在: {local_path}")
            return

        # 保存
        try:
            if self.project_id:
                self.db.update_project(self.project_id, self.server_id, name, type_, local_path, remote_path,
                                       start_command, stop_command, desc)
                messagebox.showinfo("成功", "项目信息更新成功")
                logger.info(f"更新项目: {name}")
            else:
                self.db.add_project(self.server_id, name, type_, local_path, remote_path, start_command, stop_command,
                                    desc)
                messagebox.showinfo("成功", "项目添加成功")
                logger.info(f"添加项目: {name}")

            self.parent.refresh_project_list(self.server_id)
            self.destroy()
        except Exception as e:
            messagebox.showerror("错误", f"保存失败: {str(e)}")
            logger.error(f"保存项目失败: {str(e)}")


# 部署进度窗口
class DeployProgressWindow(customtkinter.CTkToplevel):
    def __init__(self, parent, project_name):
        super().__init__(parent)
        self.title(f"部署 {project_name}")
        self.geometry("400x220")  # 略微增加高度，从200→220
        self.parent = parent

        # 确保窗口置顶显示
        self.transient(parent)
        self.grab_set()
        self.lift()

        self.init_ui()

    def init_ui(self):
        # 使用主容器增加内边距
        main_container = customtkinter.CTkFrame(self)
        main_container.pack(fill=tk.BOTH, expand=True, padx=20, pady=20)

        # 进度条
        self.progress_label = customtkinter.CTkLabel(main_container, text="准备部署...")
        self.progress_label.pack(pady=15)

        self.progress_bar = customtkinter.CTkProgressBar(main_container, width=300)
        self.progress_bar.set(0)
        self.progress_bar.pack(pady=10)

        # 状态信息
        self.status_label = customtkinter.CTkLabel(main_container, text="等待部署开始...")
        self.status_label.pack(pady=10)

        # 按钮区域
        btn_frame = customtkinter.CTkFrame(self)
        btn_frame.pack(fill=tk.X, padx=20, pady=15)

        self.cancel_btn = customtkinter.CTkButton(btn_frame, text="取消", command=self.cancel_deploy)
        self.cancel_btn.pack(pady=5)

        self.canceled = False

    def update_progress(self, value, message):
        self.progress_bar.set(value / 100)
        self.status_label.configure(text=message)
        self.update_idletasks()

    def cancel_deploy(self):
        self.canceled = True
        self.status_label.configure(text="正在取消部署...")

    def set_result(self, success, message):
        if success:
            self.status_label.configure(text=f"部署成功: {message}")
            self.progress_bar.set(1)
        else:
            self.status_label.configure(text=f"部署失败: {message}")

        self.cancel_btn.configure(text="关闭", command=self.destroy)
